package com.sdweizan.sdk.bytedance.api.impl;

import com.sdweizan.sdk.bytedance.api.BdMiniAppService;
import com.sdweizan.sdk.bytedance.api.BdService;
import com.sdweizan.sdk.bytedance.config.BdConfigStorage;
import com.sdweizan.sdk.bytedance.error.BdError;
import com.sdweizan.sdk.bytedance.error.BdErrorException;
import com.sdweizan.sdk.bytedance.error.BdRuntimeException;
import com.sdweizan.sdk.bytedance.util.RequestExecutor;

import java.util.Map;

import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public abstract class BdServiceBaseImpl implements BdService {
  @Getter protected final BdMiniAppService bdMiniAppService;

  protected BdServiceBaseImpl(BdMiniAppService bdMiniAppService) {
    this.bdMiniAppService = bdMiniAppService;
  }

  @Override
  public <T> T execute(
      String requestUri,
      Map<String, Object> requestBody,
      RequestExecutor<T, Map<String, Object>> executor)
      throws BdErrorException {
    int retryTimes = 0;
    BdConfigStorage bdConfigStorage = bdMiniAppService.getConfigStorage();
    do {
      try {
        return executeInternal(requestUri, requestBody, executor, false);
      } catch (BdErrorException e) {
        BdError error = e.getError();
        // -1 系统繁忙, 1000ms后重试
        if (error.getErrorCode().isEmpty()) {
          // 判断是否已经超了最大重试次数
          if (retryTimes + 1 > bdConfigStorage.getMaxRetryTimes()) {
            log.info("重试达到最大次数【{}】", bdConfigStorage.getMaxRetryTimes());
            // 最后一次重试失败后，直接抛出异常，不再等待
            throw new BdRuntimeException("字节服务端异常，超出重试次数");
          }

          int sleepMillis = bdConfigStorage.getRetrySleepMillis() * (1 << retryTimes);
          try {
            log.info("字节系统繁忙，{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1);
            Thread.sleep(sleepMillis);
          } catch (InterruptedException e1) {
            throw new BdRuntimeException(e1);
          }
        } else {
          throw e;
        }
      }
    } while (retryTimes++ < bdConfigStorage.getMaxRetryTimes());

    log.info("重试达到最大次数【{}】", bdConfigStorage.getMaxRetryTimes());
    throw new BdRuntimeException("字节服务端异常，超出重试次数");
  }

  protected abstract <T> T executeInternal(
      String requestUri,
      Map<String, Object> requestBody,
      RequestExecutor<T, Map<String, Object>> executor,
      boolean doNotAutoRefresh)
      throws BdErrorException;
}
